package com.itita.ww2.game.user;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.itita.ww2.redis.RedisUtil;
import com.itita.ww2.redis.cache.Table;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.itita.ww2.data.BuildingConfig;
import com.itita.ww2.data.PlayerConfig;
import com.itita.ww2.model.CodeType;
import com.itita.ww2.model.army.UserArmy.ArmyType;
import com.itita.ww2.model.building.BDBarracks;
import com.itita.ww2.model.building.BDFortification;
import com.itita.ww2.model.building.BDResource;
import com.itita.ww2.model.building.BuildingBase;
import com.itita.ww2.model.user.DevTime.DevTimeType;
import com.itita.ww2.model.user.UserProfile;

public class UserBuildingManager {
	// private static final Logger logger = LoggerFactory.getLogger(UserBuildingManager.class);
	// 
	private int uid;
	private UserProfile userProfile;
	private Map<String, BuildingBase> buildingMap; // type - building

	public UserBuildingManager(UserProfile userProfile) {
		this.userProfile = userProfile;
		this.uid = userProfile.getUid();
		buildingMap = new HashMap<>();
	}

	/**
	 * 某种建筑是否已经解锁
	 */
	public boolean isBuildingUnlocked(BuildingType type) {
		return buildingMap.containsKey(type.getValue());
	}

	/**
	 * 某种建筑是否已经解锁
	 */
	public boolean isBuildingUnlocked(ArmyType armyType) {
		return buildingMap.containsKey(BuildingType.armyTypeValueOf(armyType).getValue());
	}

	/**
	 * 根据建筑类别 获取建筑
	 */
	public BuildingBase getBuildingByType(BuildingType type) {
		return buildingMap.get(type.getValue());
	}

	/**
	 * 根据兵种类别获取对应生产建筑
	 */
	public BuildingBase getBuildingByArmyType(ArmyType type) {
		BuildingBase ret = null;
		switch (type) {
		case SOLDIER:
			ret = getBuildingByType(BuildingType.BARRACK);
			break;
		case ARMOREDVEHICLE:
			ret = getBuildingByType(BuildingType.LIGHT_ARMOR_FACTORY);
			break;
		case TANK:
			ret = getBuildingByType(BuildingType.HEAVY_ARMOR_FACTORY);
			break;
		}
		return ret;
	}

	/**
	 * 获取所有资源建筑
	 */
	public List<BDResource> getAllResBuilding() {
		List<BDResource> ret = new ArrayList<>();
		for (BuildingBase bb : this.buildingMap.values()) {
			if (bb instanceof BDResource) {
				ret.add((BDResource) bb);
			}
		}
		return ret;
	}

	/**
	 * 获取兵营
	 */
	public BDBarracks getBDBarracks() {
		return (BDBarracks) buildingMap.get(BuildingType.BARRACK.getValue());
	}

	/**
	 * 获取防御工事
	 */
	public BDFortification getBDFortification() {
		return (BDFortification) buildingMap.get(BuildingType.FORTIFICATIONS_INSTITUTE.getValue());
	}

	/**
	 * 等级条件是否匹配
	 */
	private boolean isLvMatched(BuildingType type, int lv) {
		if (!isBuildingUnlocked(type)) {
			return false;
		}
		return getBuildingByType(type).getLevel() >= lv;
	}

	/**
	 * 玩家是否能解锁某个建筑
	 */
	private boolean canUnlock(BuildingType type) {
		if (isBuildingUnlocked(type)) {
			return false;
		}
		// 资源条件
		ISFSObject costResObj = BuildingConfig.getBDUpgradeRes(type.getValue(), 0);
		if (!userProfile.getResManager().isResEnoughMulti(costResObj)) {
			return false;
		}
		// 前置条件
		ISFSObject limitObj = BuildingConfig.getBDUpgradeLimit(type.getValue(), 0);
		for (String key : limitObj.getKeys()) {
			if (CodeType.BUILDING.match(key)) { // 建筑
				if (!this.isLvMatched(BuildingType.codeValueOf(key), limitObj.getInt(key))) {
					return false;
				}
			} else if (CodeType.COMMANDER.match(key)) { // 指挥官等级
				if (limitObj.getInt(key) > userProfile.getUserInfo().getLevel()) {
					return false;
				}
			} else {
				return false;
			}
		}
		return true;
	}

	/**
	 * 解锁某种建筑
	 */
	public boolean unlockBuilding(BuildingType type) {
		if (!canUnlock(type)) {
			return false;
		}
		BuildingBase building = new BuildingBase(userProfile, type.getValue(), 1);
		switch (type) {
		case BASE:
			// userProfile.getBaseMapManager().addBA(type.getValue());
			break;
		case OILFIELD:
		case MILLS:
		case POWER_PLANT:
		case BANK:
			building = new BDResource(userProfile, type.getValue(), 1).init();
			// userProfile.getBaseMapManager().addBA(type.getValue());
			break;
		case BARRACK:
			building = new BDBarracks(userProfile, type.getValue(), 1);
			break;
		case FORTIFICATIONS_INSTITUTE:
			building = new BDFortification(userProfile, type.getValue(), 1);
			break;
		default:
			break;
		}
		this.buildingMap.put(type.getValue(), building);
		//
		update();
		// 扣除资源
		//		ISFSObject costResObj = BuildingConfig.getBDUpgradeRes(type.getValue(), 0);
		//		userProfile.getResManager().operRes(costResObj, false);
		//		userProfile.getResManager().update();
		//		userProfile.getResManager().sync();
		return true;
	}

	/**
	 * 是否可以升级,检查前置条件(包括资源条件)
	 */
	private boolean canUpgrade(BuildingType type) {
		// 解锁与否
		if (!isBuildingUnlocked(type)) {
			return false;
		}
		// 已经处于升级队列中
		if (userProfile.getTimeManager().isDevTimeExists(DevTimeType.UPGRADE, type.getValue())) {
			return false;
		}
		BuildingBase building = getBuildingByType(type);
		// 最大等级
		if (BuildingConfig.isBDLvMaximum(type.getValue(), building.getLevel())) {
			return false;
		}
		// 资源条件
		ISFSObject costResObj = BuildingConfig.getBDUpgradeRes(type.getValue(), building.getLevel());
		if (!userProfile.getResManager().isResEnoughMulti(costResObj)) {
			return false;
		}
		// 前置条件
		ISFSObject limitObj = BuildingConfig.getBDUpgradeLimit(type.getValue(), building.getLevel());
		for (String key : limitObj.getKeys()) {
			if (CodeType.BUILDING.match(key)) { // 建筑
				if (!isLvMatched(BuildingType.codeValueOf(key), limitObj.getInt(key))) {
					return false;
				}
			} else if (CodeType.COMMANDER.match(key)) { // 指挥官等级
				if (userProfile.getUserInfo().getLevel() < limitObj.getInt(key)) {
					return false;
				}
			} else {
				// 其他类别的判断(暂时没有其他类别)
				return false;
			}
		}
		return true;
	}

	/**
	 * 升级建筑
	 */
	public boolean upgrade(BuildingType type) {
		if (!canUpgrade(type)) {
			return false;
		}
		BuildingBase building = getBuildingByType(type);
		// 获取配置
		ISFSObject costResObj = BuildingConfig.getBDUpgradeRes(building.getCode(), building.getLevel());
		// 消耗资源
		userProfile.getResManager().operResWithMaxCheck(costResObj, false);
		userProfile.getResManager().update();
		// 推送消息
		userProfile.getResManager().sync();
		// 加入时间管理
		userProfile.getTimeManager().addDevTime(DevTimeType.UPGRADE, building.getCode(),
				BuildingConfig.getBDUpgradeTime(building.getCode(), building.getLevel()));
		userProfile.getTimeManager().update();
		//
		// update();
		return true;
	}

	/**
	 * 升级完成
	 */
	public boolean upgradeComplete(BuildingType type) {
		// 是否在升级队列中
		if (!userProfile.getTimeManager().isDevTimeExists(DevTimeType.UPGRADE, type.getValue())) {
			return false;
		}
		// 时间判断
		if (!userProfile.getTimeManager().isTimeup(DevTimeType.UPGRADE, type.getValue())) {
			return false;
		}
		BuildingBase building = getBuildingByType(type);
		building.levelUp(); // 等级递增
		//
		update();
		// 移除升级时间
		userProfile.getTimeManager().removeDevTime(DevTimeType.UPGRADE, building.getCode());
		userProfile.getTimeManager().update();
		return true;
	}

	public synchronized void load() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		ISFSObject bdObj = SFSObject.newFromJsonData(t.getValue(RedisUtil.genericKey(this.uid), "buildings"));
		// 
		buildingMap.clear();
		for (String key : bdObj.getKeys()) { // 目前结构就这样吧
			BuildingBase ub = BuildingBase.newFromJsonData(userProfile, key, bdObj.getSFSObject(key));
			buildingMap.put(key, ub);
		}
	}

	public synchronized void update() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		t.setValue(RedisUtil.genericKey(this.uid), "buildings", toSFSObject().toJson());
	}

	public ISFSObject toSFSObject() {
		ISFSObject ret = SFSObject.newInstance();
		for (BuildingBase ub : buildingMap.values()) {
			ret.putSFSObject(ub.getCode(), ub.toSFSObject());
		}
		return ret;
	}

	private boolean isInit() {
		com.itita.ww2.redis.cache.Table t = UserService.getInstance().getCacheUserDataTable();
		String data = t.getValue(RedisUtil.genericKey(userProfile.getUid()), "buildings");
		return StringUtils.isNotBlank(data) && !data.equals("null");
	}

	/**
	 * 初始化数据
	 */
	public void initialize() {
		if (!isInit()) {
			ISFSObject bdObj = PlayerConfig.getGameInitBuilding();
			buildingMap.clear();
			for (String key : bdObj.getKeys()) { // 目前结构就这样吧
				BuildingBase ub = BuildingBase.newFromJsonData(userProfile, key, bdObj.getSFSObject(key));
				buildingMap.put(key, ub);
			}
			this.update();
		} else {
			load();
		}
	}

	public static enum BuildingType {
		BASE("BA001"), // 基地
		BARRACK("BA002"), // 兵营
		LIGHT_ARMOR_FACTORY("BA003"), // 轻装甲工厂
		HEAVY_ARMOR_FACTORY("BA004"), // 重装甲工厂
		INFANTRY_INSTITUTE("BA005"), // 步兵研究所
		LIGHT_ARMOR_INSTITUTE("BA006"), // 轻装甲研究所
		HEAVY_ARMOR_INSTITUTE("BA007"), // 重装甲研究所
		AIR_COMMAND("BA008"), // 空指部
		HOSPITAL("BA009"), // 医院
		RADIO_INSTITUTE("BA010"), // 无线电研究所
		OILFIELD("BA011"), // 油田
		MILLS("BA012"), // 钢厂
		POWER_PLANT("BA013"), // 电厂
		BANK("BA014"), // 银行
		FORTIFICATIONS_INSTITUTE("BA015"), // 防御工事研究所
		;
		private String code;

		public String getValue() {
			return this.code;
		}

		private BuildingType(String code) {
			this.code = code;
		}

		public static BuildingType codeValueOf(String code) {
			for (BuildingType bt : values()) {
				if (bt.code.equals(code)) {
					return bt;
				}
			}
			return null;
		}

		public static BuildingType armyTypeValueOf(ArmyType type) {
			BuildingType ret = null;
			switch (type) {
			case SOLDIER:
				ret = BARRACK;
				break;
			case ARMOREDVEHICLE:
				ret = BuildingType.LIGHT_ARMOR_FACTORY;
				break;
			case TANK:
				ret = BuildingType.HEAVY_ARMOR_FACTORY;
				break;
			}
			return ret;
		}

		public static BuildingType resCodeValueOf(String code) {
			code = code.replace("R", "BA");
			return codeValueOf(code);
		}
	}
}
